package main

import (
	"fmt"
	"time"
	"runtime"
	"sync"
	"sync/atomic"
//	"math/rand"
//	"os"
//	"strings"
//	"regexp"
)

func main(){
	fmt.Println(time.Now())
	fmt.Println("runtime.NumCPU():",runtime.NumCPU())
	fmt.Println("runtime.NumGoroutine():",runtime.NumGoroutine())
	fmt.Println("runtime.CPUProfile():",runtime.CPUProfile())
	fmt.Println("runtime.GOOS:",runtime.GOOS)
	fmt.Println("runtime.GOROOT():",runtime.GOROOT())
	fmt.Println("runtime.NumCgoCall():",runtime.NumCgoCall())
	fmt.Println("runtime.Version():",runtime.Version())
	
	runtime.GOMAXPROCS(runtime.NumCPU())
	concurrentAccessIntByLock()
}

func concurrentAccessInt(){
	fmt.Println("----------concurrentAccessInt----------")
	//this is very important and it will make system application use real multil-thread instread of multi-goroutine
	//首先要保证runtime.GOMAXPROCS(runtime.NumCPU())，打开真正的多线程
	//其次要多个routine同时开始操作一个int，为了保证并行，他们都在开始前sleep一秒钟
	//程序运行最终的结果不是1000，而是小于1000，这就显示了是因为并发而没有同步导致了问题
//	runtime.GOMAXPROCS(runtime.NumCPU())
	var i,count int = 0,1000
	var c chan int=make(chan int,count)
	fmt.Println("initial i=",i)
	for n:=0;n<count;n++{
		go func(x *int){
			time.Sleep(time.Second)
			*x++
			c<-n
		}(&i)
	}
	for n:=0;n<count;n++{
		<-c
	}
	fmt.Println("end i=",i)
}

func concurrentAccessAtomicInt(){
	fmt.Println("----------concurrentAccessAtomicInt----------")
	//this is very important and it will make system application use real multil-thread instread of multi-goroutine
//	runtime.GOMAXPROCS(runtime.NumCPU())
	var i,count int32 = 0,1000
	var c chan int32=make(chan int32,count)
	fmt.Println("initial i=",i)
	var n int32
	for n=0;n<count;n++{
		go func(x *int32){
			time.Sleep(time.Second)
			//方法atomic.AddInt32是个原子操作方法，就是说即使多个线程同时调用它操作同一int32，执行时依然是互斥的。不会发生最后结果小于count值。
			//sync.atomic包设计成专门处理原子操作，java中也有类似的机制，非常相像。
			atomic.AddInt32(&i,1)
			//这里如果换成*x++，即不使用atomic，那么在真正的多线程下结果必然小于count
//			*x++
			c<-n
		}(&i)
	}
	for n=0;n<count;n++{
		<-c
	}
	fmt.Println("end i=",i)
	
}

var l sync.Mutex=sync.Mutex{}

func concurrentAccessIntByLock(){
	fmt.Println("----------concurrentAccessIntByLock----------")
	//this is very important and it will make system application use real multil-thread instread of multi-goroutine
//	runtime.GOMAXPROCS(runtime.NumCPU())
	var i,count int32 = 0,1000
	var c chan int32=make(chan int32,count)
	fmt.Println("initial i=",i)
	var n int32
	for n=0;n<count;n++{
		go func(x *int32){
			time.Sleep(time.Second)
			l.Lock()
			//这里如果换成*x++，即不使用atomic，那么在真正的多线程下结果必然小于count
			*x++
			l.Unlock()
			c<-n
		}(&i)
	}
	for n=0;n<count;n++{
		<-c
	}
	fmt.Println("end i=",i)
	
}
